<?php

class YougoRestClient {

    private static $instance;
    private $sfWebBrowser;
    private $serverUrl = 'http://localhost:8080';
    private $apiPath = '/yougo-rest/api';
    private $defaultHeaders = array('Content-Type' => 'application/json');

    private function __construct($user = null, $password = null) {
        if ($user == null && $password == null)
            $authHeader = array('Authorization' => 'Basic ' . sfContext::getInstance()->getUser()->getBasicAuth());
        else
            $authHeader = array('Authorization' => 'Basic ' . base64_encode($user . ':' . $password));
        $headers = array_merge($this->defaultHeaders, $authHeader);
        $this->sfWebBrowser = new sfWebBrowser($headers);
    }

    /**
     * @return YougoRestClient
     */
    public static function singleton() {
        if (!isset(self::$instance)) {
            self::$instance = new YougoRestClient();
        }
        return self::$instance;
    }

    /**
     * @return YougoRestClient
     */
    public static function init($email, $password) {
        self::$instance = new YougoRestClient($email, $password);
    }

    /**
     * @return sfWebBrowser
     */
    public function get($uri, $parameters = null, $headers = array()) {
        try {
            $b = $this->sfWebBrowser->get($this->serverUrl . $this->apiPath . $uri, $parameters, $headers);
            $this->debug('GET', $this->serverUrl . $this->apiPath . $uri, $parameters, $headers, $b->getResponseCode());
        } catch (Exception $e) {
            $this->serverAccessError($e);
        }

        if ($b->getResponseCode() >= 500)
            $this->serverError($b);
        if ($b->getResponseCode() >= 400)
            $this->clientError($b);

        return $b;
    }

    /**
     * @return sfWebBrowser
     */
    public function post($uri, $parameters = null, $headers = array()) {
        try {
            $b = $this->sfWebBrowser->post($this->serverUrl . $this->apiPath . $uri, $parameters, $headers);
            $this->debug('POST', $this->serverUrl . $this->apiPath . $uri, $parameters, $headers, $b->getResponseCode());
        } catch (Exception $e) {
            $this->serverAccessError($e);
        }

        if ($b->getResponseCode() >= 500)
            $this->serverError($b);
        if ($b->getResponseCode() >= 400)
            $this->clientError($b);

        return $b;
    }

    /**
     * @return sfWebBrowser
     */
    public function put($uri, $parameters = null, $headers = array()) {
        try {
            $b = $this->sfWebBrowser->put($this->serverUrl . $this->apiPath . $uri, $parameters, $headers);
            $this->debug('PUT', $this->serverUrl . $this->apiPath . $uri, $parameters, $headers, $b->getResponseCode());
        } catch (Exception $e) {
            $this->serverAccessError($e);
        }

        if ($b->getResponseCode() >= 500)
            $this->serverError($b);
        if ($b->getResponseCode() >= 400)
            $this->clientError($b);

        return $b;
    }

    /**
     * @return sfWebBrowser
     */
    public function delete($uri, $parameters = null, $headers = array()) {
        try {
            $b = $this->sfWebBrowser->delete($this->serverUrl . $this->apiPath . $uri, $parameters, $headers);
            $this->debug('DELETE', $this->serverUrl . $this->apiPath . $uri, $parameters, $headers, $b->getResponseCode());
        } catch (Exception $e) {
            $this->serverAccessError($e);
        }

        if ($b->getResponseCode() >= 500)
            $this->serverError($b);
        if ($b->getResponseCode() >= 400)
            $this->clientError($b);

        return $b;
    }

    private function serverError($b) {
        sfContext::getInstance()->getLogger()->err(sprintf('{YougoRestClient} ServerError %s : %s', $b->getResponseCode(), $b->getResponseMessage()));
        throw new YougoServerException($b->getResponseCode() . ' ' . $b->getResponseMessage());
    }

    private function clientError($b) {
        sfContext::getInstance()->getLogger()->err(sprintf('{YougoRestClient} ClientError %s : %s', $b->getResponseCode(), $b->getResponseMessage()));
        throw new YougoClientException($b->getResponseCode() . ' ' . $b->getResponseMessage());
    }

    private function serverAccessError(Exception $e) {
        sfContext::getInstance()->getLogger()->err('{YougoRestClient} ServerError : YouGO server on ' . $this->serverUrl . $this->apiPath . ' unreachable. ' . $e->getMessage());
        throw new YougoServerException($e->getMessage());
    }

    private function debug($verb, $uri, $parameters, $headers, $responseCode) {
        if (is_array($parameters))
            $parameters = json_encode($parameters);
        else
            $parameters = '"' . $parameters . '"';

        if (is_array($headers))
            $headers = json_encode($headers);

        sfContext::getInstance()->getLogger()->debug('{YougoRestClient} ' . $verb . ': ' . $uri . ' ' . $parameters . ' ' . $headers . ' - ' . $responseCode);
    }

}
